﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SCSEngine.ScreenManagement.Implement;
using SCSEngine.ScreenManagement;
using SCSEngine.ResourceManagement;
using SCSEngine.Services;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics;
using Microsoft.Devices.Sensors;
using FarseerPhysics.Common;
using FarseerPhysics.Camera;
using SCSEngine.Audio;

namespace TriUan.TriUanGame.GameScreen
{
    class ShakeScreen: BaseGameScreen, ShakeListener
    {
        const int A = 105;
        private SCSServices services;
        bool start = false;
        private IResourceManager resourceManager;

        Sound sound;

        Camera2D camera;

        private readonly World _world;

        /// <summary>
        /// Body của các mảnh ghép
        /// </summary>
        private Body b1, b2, b3, b4, b5, b6, b7;
        /// <summary>
        /// Ảnh của 7 miếng ghép
        /// </summary>
        private Texture2D t1, t2, t3, t4, t5, t6, t7;

        /// <summary>
        /// Ảnh Nền
        /// </summary>
        private Texture2D background;


        /// <summary>
        /// Tâm của 7 miếng ghép tương ứng
        /// </summary>
        Vector2 c1, c2, c3, c4, c5, c6, c7;
        /// <summary>
        /// Trung tâm của màn hình
        /// </summary>
        private Vector2 center_src;

        /// <summary>
        /// Use sensor 
        /// </summary>
        SensorHelper sensor;
        


        public ShakeScreen(IGameScreenManager manager)
            : base(manager)
        {
            services = (SCSServices)manager.GamePage.Services.GetService(typeof(SCSServices));

            resourceManager = (IResourceManager)manager.GamePage.Services.GetService(typeof(IResourceManager));
            _world = new World(new Vector2(0, 0));

            this.Renew();
            Initialize();
        }

        private void InitiData(ref Texture2D t, ref Body b, Vector2 delta, ref Vector2 c)
        {
            uint[] data = new uint[t.Width * t.Height];
            t.GetData(data);
            Vertices v = PolygonTools.CreatePolygon(data, t.Width);
            c = v.GetCentroid();
            v.Translate(-c);
            v = Vertices.ToSimulatorDislay(ref v);
            b = BodyFactory.CreatePolygon(_world, v, 1.0f, ConvertUnits.ToSimUnits(center_src + delta));
            b.BodyType = BodyType.Dynamic;
            b.Restitution = 0.7f;
            b.Friction = 0.1f;
        }

       public override void  Initialize()
       {
 	
         //   camera = new Camera2D(GraphicsDevice.Viewport, 800, 480, 1.0f);

            center_src = new Vector2(800, 480) / 2f;

            #region Load Texture
            t1 = resourceManager.GetResource<Texture2D>("1");
            t2 = resourceManager.GetResource<Texture2D>("2");
            t3 = resourceManager.GetResource<Texture2D>("3");
            t4 = resourceManager.GetResource<Texture2D>("4");
            t5 = resourceManager.GetResource<Texture2D>("5");
            t6 = resourceManager.GetResource<Texture2D>("6");
            t7 = resourceManager.GetResource<Texture2D>("7");
            background = resourceManager.GetResource<Texture2D>("ShakeBg");
            sound = resourceManager.GetResource<Sound>("sound1");

            #endregion

            ///Convert to Physic simulator Unit
            ConvertUnits.SetDisplayUnitToSimUnitRatio(64f);

            #region Tao cac polygon
            InitiData(ref t1, ref b1, Vector2.Zero, ref c1);
            InitiData(ref t2, ref b2, new Vector2(50, 5), ref c2);
            InitiData(ref t3, ref b3, new Vector2(-50, 2), ref c3);
            InitiData(ref t4, ref b4, new Vector2(20, 5), ref c4);
            InitiData(ref t5, ref b5, new Vector2(-20, 20), ref c5);
            InitiData(ref t6, ref b6, new Vector2(28, -20), ref c6);
            InitiData(ref t7, ref b7, new Vector2(-20, 2), ref c7);
            #endregion

            #region Play sound when collision
            b1.OnCollision += b1_OnCollision;
            b2.OnCollision += b2_OnCollision;
            b3.OnCollision += b3_OnCollision;
            b4.OnCollision += b4_OnCollision;
            b5.OnCollision += b5_OnCollision;
            b6.OnCollision += b6_OnCollision;
            b7.OnCollision += b7_OnCollision;

            b1.OnSeparation += b1_OnSeparation;
            b2.OnSeparation += b2_OnSeparation;
            b3.OnSeparation += b3_OnSeparation;
            b4.OnSeparation += b4_OnSeparation;
            b5.OnSeparation += b5_OnSeparation;
            b6.OnSeparation += b6_OnSeparation;
            b7.OnSeparation += b7_OnSeparation;
            // b3, b...b7 is similar
            #endregion
           
            #region Tạo các cạnh ở 4 góc màn hình để ngăn cản trường hợp 2 cái hình nó chạy vượt ra khỏi màn hình; Canh nay nam ngay tren may thanh tre
            BodyFactory.CreateEdge(_world, ConvertUnits.ToSimUnits(new Vector2(50, 50)), ConvertUnits.ToSimUnits(new Vector2(50, (float)480 - 50)));
            BodyFactory.CreateEdge(_world, ConvertUnits.ToSimUnits(new Vector2((float)800 - 50, 50)), ConvertUnits.ToSimUnits(new Vector2((float)800 - 50, (float)480 - 50)));
            BodyFactory.CreateEdge(_world, ConvertUnits.ToSimUnits(new Vector2(50, (float)480 - 50)), ConvertUnits.ToSimUnits(new Vector2((float)800 - 50, (float)480 - 50)));
            BodyFactory.CreateEdge(_world, ConvertUnits.ToSimUnits(new Vector2(50, 50)), ConvertUnits.ToSimUnits(new Vector2((float)800 - 50, 50)));
            #endregion

            sensor = new SensorHelper(new Accelerometer());
            sensor.activate((ShakeListener)this);


        }
       void b7_OnSeparation(Fixture fixtureA, Fixture fixtureB)
       {
          // sound.Stop();
       }

       void b6_OnSeparation(Fixture fixtureA, Fixture fixtureB)
       {
           //sound.Stop();
       }

       void b5_OnSeparation(Fixture fixtureA, Fixture fixtureB)
       {
           //sound.Stop();
       }

       void b4_OnSeparation(Fixture fixtureA, Fixture fixtureB)
       {
           //sound.Stop();
       }

       void b3_OnSeparation(Fixture fixtureA, Fixture fixtureB)
       {
           //sound.Stop();
       }

        void b2_OnSeparation(Fixture fixtureA, Fixture fixtureB)
        {
            //sound.Stop();
        }

        void b1_OnSeparation(Fixture fixtureA, Fixture fixtureB)
        {
            //sound.Stop();
        }

        /// <summary>
        /// return true if want to handle collision
        /// </summary>
        /// <param name="fixtureA"></param>
        /// <param name="fixtureB"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        bool b7_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            //sound.Play();
            return true;
        }
        /// <summary>
        /// return true if want to handle collision
        /// </summary>
        /// <param name="fixtureA"></param>
        /// <param name="fixtureB"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        bool b6_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            //sound.Play();
            return true;
        }
        /// <summary>
        /// return true if want to handle collision
        /// </summary>
        /// <param name="fixtureA"></param>
        /// <param name="fixtureB"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        bool b5_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            //sound.Play();
            return true;
        }
        /// <summary>
        /// return true if want to handle collision
        /// </summary>
        /// <param name="fixtureA"></param>
        /// <param name="fixtureB"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        bool b4_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            //sound.Play();
            return true;
        }
        /// <summary>
        /// return true if want to handle collision
        /// </summary>
        /// <param name="fixtureA"></param>
        /// <param name="fixtureB"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        bool b3_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            //sound.Play();
            return true;
        }
        /// <summary>
        /// return true if want to handle collision
        /// </summary>
        /// <param name="fixtureA"></param>
        /// <param name="fixtureB"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        bool b2_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            //sound.Play();
            return true;
        }

        /// <summary>
        /// return true if want to handle collision
        /// </summary>
        /// <param name="fixtureA"></param>
        /// <param name="fixtureB"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        bool b1_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            //sound.Play();
            return true;
        } 


        public override void Update(GameTime gameTime)
        {
            _world.Step((float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.001f);
            foreach (Body b in _world.BodyList)
                if (b.LinearVelocity.Length() < 1)
                    ApplyForce(b);

            base.Update(gameTime);
        }

        private void Renew()
        {
            Components.Clear();
        }

        public override void Draw(GameTime gameTime)
        {
            #region Ve hinh background
            services.SpriteBatch.Draw(background, Vector2.Zero, Color.White);
            #endregion

            #region Vẽ Hình len man hinh

            services.SpriteBatch.Draw(t1, ConvertUnits.ToDisplayUnits(b1.Position), null, Color.White, b1.Rotation, c1, 1.0f, SpriteEffects.None, 0f);
            services.SpriteBatch.Draw(t2, ConvertUnits.ToDisplayUnits(b2.Position), null, Color.White, b2.Rotation, c2, 1.0f, SpriteEffects.None, 0f);
            services.SpriteBatch.Draw(t3, ConvertUnits.ToDisplayUnits(b3.Position), null, Color.White, b3.Rotation, c3, 1.0f, SpriteEffects.None, 0f);
            services.SpriteBatch.Draw(t4, ConvertUnits.ToDisplayUnits(b4.Position), null, Color.White, b4.Rotation, c4, 1.0f, SpriteEffects.None, 0f);
            services.SpriteBatch.Draw(t5, ConvertUnits.ToDisplayUnits(b5.Position), null, Color.White, b5.Rotation, c5, 1.0f, SpriteEffects.None, 0f);
            services.SpriteBatch.Draw(t6, ConvertUnits.ToDisplayUnits(b6.Position), null, Color.White, b6.Rotation, c6, 1.0f, SpriteEffects.None, 0f);
            services.SpriteBatch.Draw(t7, ConvertUnits.ToDisplayUnits(b7.Position), null, Color.White, b7.Rotation, c7, 1.0f, SpriteEffects.None, 0f);

            #endregion

            base.Draw(gameTime);
        }

        public void shakeStarted()
        {
            #region Start moving 7 image
            b1.ApplyForce(A * (new Vector2(sensor.Acceleration.X, sensor.Acceleration.Y)));
            b2.ApplyForce(A * (new Vector2(sensor.Acceleration.X, sensor.Acceleration.Y)));
            b3.ApplyForce(A * (new Vector2(sensor.Acceleration.X, sensor.Acceleration.Y)));
            b4.ApplyForce(A * (new Vector2(sensor.Acceleration.X, sensor.Acceleration.Y)));
            b5.ApplyForce(A * (new Vector2(sensor.Acceleration.X, sensor.Acceleration.Y)));
            b6.ApplyForce(A * (new Vector2(sensor.Acceleration.X, sensor.Acceleration.Y)));
            b7.ApplyForce(A * (new Vector2(sensor.Acceleration.X, sensor.Acceleration.Y)));
            start = true;
            //last_time = 0;
            #endregion
        }

        private void ApplyForce( Body b)
        {
            Vector2 f = center_src - ConvertUnits.ToDisplayUnits(b.Position);
            f.Normalize();
            b.ApplyForce(f);
        }
        
        
    }
}
